#include "CommunicateMgr.h"
#include "DevDataMgr.h"

#include "anthResponse.h"
#include "requirePackage.h"
#include "dataPackage.h"

CommunicateMgr* CommunicateMgr::s_head = NULL;

CommunicateMgr::CommunicateMgr() {
	isRight = true;
	total = 0;
	TotalSockets = 0;
	TotalPorts = 0;
	packageType = 0x00;
	Ret = 0;

	NonBlock = 0;

	SendBytes = 0;
	RecvBytes = 0;

	ListenSocket = NULL;
	AcceptSocket = NULL;
	
	InternetAddr.sin_family = AF_INET;
	InternetAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
	InternetAddr.sin_port = htons(PORT_NUM);
	
	memset(SocketArray, 0, sizeof(SocketArray));
	memset(PortsArray, 0, sizeof(PortsArray));
}

CommunicateMgr::~CommunicateMgr() {
	delete(s_head);
}

CommunicateMgr* CommunicateMgr::getIt() {
	if (s_head == NULL) {
		s_head = new(CommunicateMgr);
	}
	return s_head;
}

bool CommunicateMgr::creatSocketInformation(SOCKET s) {
	LPSOCKET_INFOMATION SI;

	if ((SI = (LPSOCKET_INFOMATION)GlobalAlloc(GPTR, sizeof(SOCKET_INFORMATION))) == NULL) {
		printf_s("GlobalAlloc() failed with error %d\n", GetLastError());
		return false;
	}

	SI->Socket = s;
	SI->BytesRecv = 0;
	SI->BytesSend = 0;

	SocketArray[TotalSockets] = SI;
	TotalSockets++;

	return true;
}

void CommunicateMgr::init() {
	if ((Ret = WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0) {
		printf_s("WSAStarup() failed with error %d\n", Ret);
		WSACleanup();
		isRight = false;
	}

	if ((ListenSocket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET) {
		printf_s("WSASocket() failed with error %d\n", WSAGetLastError());
		isRight = false;
	}

	if (bind(ListenSocket, (PSOCKADDR)& InternetAddr, sizeof(InternetAddr)) == SOCKET_ERROR) {
		printf_s("bind() failed with error %d\n", WSAGetLastError());
		isRight = false;
	}

	if (listen(ListenSocket, BACKLOG_NUM)) {
		printf_s("listen() failed with error %d\n", WSAGetLastError());
		isRight = false;
	}

	NonBlock = 1;

	if (ioctlsocket(ListenSocket, FIONBIO, &NonBlock) == SOCKET_ERROR) {
		printf_s("ioctlsocket() failed with %d \n", WSAGetLastError());
		isRight = false;
	}

	creatSocketInformation(ListenSocket);
}

void CommunicateMgr::freeSocketInformation(int Index) {
	LPSOCKET_INFOMATION SI = SocketArray[Index];
	int i = 0;

	closesocket(SI->Socket);
	GlobalFree(SI);

	if (Index != (TotalSockets - 1)) {
		for (i = Index; i < TotalSockets; i++) {
			SocketArray[i] = SocketArray[i + 1];
		}
	}

	TotalSockets--;
}

void CommunicateMgr::creatPortInformation(LPSOCKET_INFOMATION s, unsigned char* devId) {
	if (s->useTime == 0) {
		PortsArray[TotalPorts].socketRecode = s->Socket;
		//strcpy_s((const char*)PortsArray[TotalPorts]->devId, (const char*)devId);
		strcpy_s((char*)PortsArray[TotalPorts].devId, sizeof(devId), (const char*)devId);
		TotalPorts++;
		s->useTime++;
	}
}

bool CommunicateMgr::runSever() {
	printf_s("start Communicate\n");
	init();
	while (isRight) {
		FD_ZERO(&ReadSet);
		FD_ZERO(&WriteSet);

		FD_SET(ListenSocket, &ReadSet);

		for (int i = 0; i < TotalSockets; i++) {
			LPSOCKET_INFOMATION SocketInfo = SocketArray[i];
			FD_SET(SocketInfo->Socket, &ReadSet);
			FD_SET(SocketInfo->Socket, &WriteSet);
		}

		if ((total = select(0, &ReadSet, &WriteSet, NULL, NULL)) == SOCKET_ERROR) {
			printf_s("selcet() failed with %d\n", WSAGetLastError());
			return false;
		}

		for (int i = 0; i < TotalSockets; i++) {
			LPSOCKET_INFOMATION SocketInfo = SocketArray[i];

			if (FD_ISSET(SocketInfo->Socket, &ReadSet)) {
				if (SocketInfo->Socket == ListenSocket) {
					total--;

					if ((AcceptSocket = accept(ListenSocket, NULL, NULL)) != INVALID_SOCKET) {
						NonBlock = 1;

						if (ioctlsocket(AcceptSocket, FIONBIO, &NonBlock) == SOCKET_ERROR) {
							printf_s("ioctlsocket() failed with %d\n", WSAGetLastError());
							return false;
						}

						if (creatSocketInformation(AcceptSocket) == FALSE) {
							return false;
						}
					}
					else {
						if (WSAGetLastError() != WSAEWOULDBLOCK) {
							printf_s("accept() failed with error %d\n", WSAGetLastError());
							return false;
						}
					}
				}
				else {
					total--;

					memset(SocketInfo->buffer, 0, BUFFER_SIZE);
					SocketInfo->Databuf.buf = SocketInfo->buffer;
					SocketInfo->Databuf.len = BUFFER_SIZE;

					DWORD flags = 0;

					if (WSARecv(SocketInfo->Socket, &(SocketInfo->Databuf), 1, &RecvBytes, &flags, NULL, NULL) == SOCKET_ERROR) {
						if (WSAGetLastError() != WSAEWOULDBLOCK) {
							printf_s("WSARecv() failed with error %d\n", WSAGetLastError());
							freeSocketInformation(i);
						}
						continue;
					}
					else {
						SocketInfo->BytesRecv = RecvBytes;
						SocketInfo->Databuf.buf[RecvBytes] = '\0';
						if (RecvBytes == 0) {
							freeSocketInformation(i);
							continue;
						}
						else {
							printf_s("recve package\n");
							//printf_s("contain : %x\n", SocketInfo->Databuf.buf);
							if ((DevDataMgr::getIt()->init(SocketInfo->Databuf.buf, packageType)) == false) {
								freeSocketInformation(i);
								continue;
							}
							if (packageType == PACKAGE_AUTHREQ) {
								printf_s("requirePackage\n");
								requirePackage* package = (requirePackage*)DevDataMgr::getIt()->getPackage();
								if (package->decipherPas()) {
									creatPortInformation(SocketArray[i], package->getDevIdValue());
									Package* packages = new authResponse(0, 0x00);
						
									packages->setIdentValue(0x7F7F);
									packages->setVersionValue(0x01);
									packages->setTypeValue(0x11);
									packages->setSessinIdValue(package->getSessinIdValue());
									packages->setSizeValue(8);
									
									//strcpy_s(SocketInfo->buffer, sizeof(authResponse), (const char*)package);
									memcpy_s(SocketInfo->buffer, sizeof(authResponse), (const char*)package, sizeof(authResponse));

									delete(packages);
								}
								else {
									freeSocketInformation(i);
								}
								delete(package);
							}
							if (packageType == PACKAGE_DATAREQ) {
								printf_s("dataPackage\n");
								dataPackage* package = (dataPackage*)DevDataMgr::getIt()->getPackage();
								for (int i = 0; i != TotalPorts; i++) {
									if (PortsArray[i].socketRecode == SocketInfo->Socket) {
										DevDataMgr::getIt()->setValue(package, PortsArray[i].devId);
										printf_s("\n\n\n write data\n\n\n\n");
										break;
									}
								}
							}
						}
					}
				}
			}
			else {
				if (FD_ISSET(SocketInfo->Socket, &WriteSet)) {
					total--;

					SocketInfo->Databuf.buf = SocketInfo->buffer + SocketInfo->BytesSend;
					SocketInfo->Databuf.len = SocketInfo->BytesRecv - SocketInfo->BytesSend;

					if (SocketInfo->Databuf.len > 0) {
						if (WSASend(SocketInfo->Socket, &(SocketInfo->Databuf), 1, &SendBytes, 0, NULL, NULL) == SOCKET_ERROR) {
							if (WSAGetLastError() != WSAEWOULDBLOCK) {
								printf_s("WSASend() failed with error %d\n", WSAGetLastError());
								freeSocketInformation(i);
							}
							continue;
						}
						else {
							SocketInfo->BytesSend += SendBytes;

							if (SocketInfo->BytesSend == SocketInfo->BytesRecv) {
								SocketInfo->BytesSend = 0;
								SocketInfo->BytesRecv = 0;
							}
						}
					}
				}
			}
		}
	}
}